/*
 * TcpServerConn.cpp
 *
 *   Created on: 2010-1-28     
 *  Description: 
 *    Copyright: 2010 @ ICT Li Heyuan
 */

#include "../../include/conn/TcpConn.h"
#include "../../include/server/Server.h"
#include "../../include/server/TcpServer.h"
#include "../../include/util/Util.h"
#include "../../include/method/RpcMethod.h"
#include "../../include/thread/JobPoll.h"

#include <unistd.h>

#include <string>
using std::string;

TcpConn::TcpConn(Server *server, int sock, const EasyAddr &addr) :
	Conn(server, sock, addr), _stage(STAGE_READ), _nSendLeft(0)
{
}

TcpConn::~TcpConn()
{
	//直接交给~Conn()处理
}

bool TcpConn::handle(unsigned int event)
{
	try
	{
		int ret = true;

		//根据事件进行选择
		switch (event)
		{
		//EPOLLIN可能是read ready或者断开了连接
		case TcpServer::EPOLL_IN:
		{
			//读ready事件，如果处于STAGE_READ，则读取
			if (_stage == STAGE_READ)
			{
				ret = handle_read();
			}
			else
			{
				//不在读阶段如果eof了，就false,不继续监视
				ret = !isEOF();
			}
		}
			break;
			//Method执行完毕，callback
		case JobPoll::FINISH:
		{
			handle_execute_finish();
			//模拟EPOLL_OUT发生了
			ret = handle(TcpServer::EPOLL_OUT);
		}
			break;
			//write ready
		case TcpServer::EPOLL_OUT:
		{
			//写ready事件，如果处于STAGE_WRITE，则写入
			if (_stage == STAGE_WRITE)
			{
				ret = handle_write();
			}
			else if (_stage == STAGE_FINISH)
			{
				ret = false;
			}
			else
			{
				//不在写阶段,也没有结束,什么也不做
			}
		}
			break;
		}

		return ret;
	} catch (...)
	{
		//出错，不继续监听
		return false;
	}
}

bool TcpConn::handle_read()
{

	bool eof = false;

	if (!Network::recvBytes(_sock, _rcvBuf, eof))
	{
		//出错
		_server->getNetLogger().error("fd=%d %s:%d recv() fail : %s", _sock,
				_addr.ip.c_str(), _addr.port,
				Util::getInstance()->getErrMsg().c_str());
		return false;
	}
	else
	{
		if (eof)
		{
			//表示socket已经关闭，无需继续moniter
			return false;
		}
		else
		{
			//成功读取了数据，判断数据是否是合法的json数据
			try
			{
				bool parseRet = _jsonReader.parse(_rcvBuf, _jsonReq);
				FastWriter writer;
				if (parseRet && !_jsonReq.isNull() && _jsonReq.isObject())//必须是object才算成功
				{
					//解析成功，转向执行阶段
					_stage = STAGE_EXECUTE;

					_server->getJsonRpcLogger().info(
							"fd=%d %s:%d get json-rpc request.\n%s", _sock,
							_addr.ip.c_str(), _addr.port, Util::replaceLine(
									_rcvBuf).c_str());

					//清空buf
					_rcvBuf.clear();

					//转向执行处理
					handle_execute();
				}
			} catch (...)
			{
				//解析出错，忽略，下次继续解析
			}

			//继续监听
			return true;
		}
	}
}

bool TcpConn::handle_write()
{
	//notification直接结束
	if (_isNotification)
	{
		//notification需要Server主动关闭
		return false;
	}

	if (!Network::sendBytes(_sock, _sendBuf, _nSendLeft))
	{
		//cerr << "fd=" << fd << ",send出错" << Util::getErrMsg() << endl;
		_server->getNetLogger().error("fd=%d %s:%d send() fail : %s", _sock,
				_addr.ip.c_str(), _addr.port,
				Util::getInstance()->getErrMsg().c_str());
		return false;
	}
	else
	{
		if (_nSendLeft)
		{
			//没有写入完毕，继续监控
			return true;
		}
		else
		{
			//写入完毕，不用继续监控了
			_server->getJsonRpcLogger().info(
					"fd=%d %s:%d send() %ld bytes finish", _sock,
					_addr.ip.c_str(), _addr.port, _sendBuf.size());
			_sendBuf.clear();
			//判断是否需要主动关闭
			if (_server->isCloseFirst())
			{
				return false;
			}
			else
			{
				return true;
			}
		}
	}
}

void TcpConn::handle_execute()
{
	//加入JobPoll异步执行
	JobPoll::getInstance()->addJob(this);
}

void TcpConn::handle_execute_finish()
{
	//json->string & 状态转换
	_sendBuf = _jsonWriter.write(_jsonResp);
	_stage = STAGE_WRITE;
	_nSendLeft = _sendBuf.size();

	//Notification不应该返回任何信息
	if (_jsonReq["id"] == Json::nullValue)
	{
		_isNotification = true;
		_sendBuf.clear();
		_stage = STAGE_FINISH;

		if (_exeSuccess)
		{
			_server->getJsonRpcLogger().info(
					"fd=%d %s:%d execute method(notification) success", _sock,
					_addr.ip.c_str(), _addr.port);
		}//end if notifition success
		else
		{
			_server->getJsonRpcLogger().error(
					"fd=%d %s:%d execute method(notification) fail : %s ",
					_sock, _addr.ip.c_str(), _addr.port, _exeError.c_str());
		}//end if notifition fail
	}//end if notification
	else
	{
		if (_exeSuccess)
		{
			_server->getJsonRpcLogger().info(
					"fd=%d %s:%d execute method(call) success\n%s", _sock,
					_addr.ip.c_str(), _addr.port,
					Util::replaceLine(_sendBuf).c_str());
		}//end if call success
		else
		{
			_server->getJsonRpcLogger().error(
					"fd=%d %s:%d execute method(call) fail : %s \n%s", _sock,
					_addr.ip.c_str(), _addr.port, _exeError.c_str(),
					Util::replaceLine(_sendBuf).c_str());
		}//end if call fail
	}//end if call
}

